package com.example.scribe.backend.handlers;

import com.example.scribe.SyntaxNode;
import com.example.scribe.backend.BytecodeOps;
import com.example.scribe.backend.ExpressionEmitter;
import com.example.scribe.backend.ExpressionNodeHandler;
import com.example.scribe.backend.LocalVariableAllocator;
import net.bytebuddy.implementation.bytecode.StackManipulation;
import net.bytebuddy.implementation.bytecode.StackManipulation.Compound;

/**
 * Handler for arithmetic expressions (addition, subtraction, multiplication, division).
 */
public final class ArithmeticExpressionHandler implements ExpressionNodeHandler {
    private final ExpressionEmitter exprEmitter;

    public ArithmeticExpressionHandler(ExpressionEmitter exprEmitter) {
        this.exprEmitter = exprEmitter;
    }

    @Override
    public boolean canHandle(String nodeType) {
        return "addition".equals(nodeType) || "subtraction".equals(nodeType) || 
               "multiplication".equals(nodeType) || "division".equals(nodeType);
    }

    @Override
    public StackManipulation handle(SyntaxNode node, String generatedClassName, LocalVariableAllocator locals) {
        if (node == null) {
            return StackManipulation.Trivial.INSTANCE;
        }
        
        String nodeType = node.type();
        
        // If multiplication node has only one child, just emit it (no operator)
        if ("multiplication".equals(nodeType) && node.children().size() == 1) {
            return exprEmitter.emit(node.children().get(0), generatedClassName, locals);
        }
        
        // For operations with operators, need at least 3 children
        if (node.children().size() < 3) {
            return StackManipulation.Trivial.INSTANCE;
        }

        StackManipulation left = exprEmitter.emit(node.children().get(0), generatedClassName, locals);
        StackManipulation right = exprEmitter.emit(node.children().get(2), generatedClassName, locals);

        if ("multiplication".equals(nodeType)) {
            // Check for division or modulo operator in multiplication node
            String op = null;
            if (node.children().size() >= 2) {
                SyntaxNode mid = node.children().get(1);
                op = mid.text();
            }
            if ("/".equals(op)) {
                return new Compound(left, right, BytecodeOps.idiv());
            } else if ("%".equals(op)) {
                return new Compound(left, right, BytecodeOps.irem());
            }
            // Default to multiplication
            return new Compound(left, right, BytecodeOps.imul());
        } else if ("division".equals(nodeType)) {
            return new Compound(left, right, BytecodeOps.idiv());
        } else if ("subtraction".equals(nodeType)) {
            return new Compound(left, right, BytecodeOps.isub());
        } else if ("addition".equals(nodeType)) {
            // Check for subtraction operator in addition node
            String op = null;
            if (node.children().size() >= 2) {
                SyntaxNode mid = node.children().get(1);
                op = mid.text();
            }
            if ("-".equals(op)) {
                return new Compound(left, right, BytecodeOps.isub());
            }
            return new Compound(left, right, BytecodeOps.iadd());
        }

        return StackManipulation.Trivial.INSTANCE;
    }
}

